/* 定义部分的文字块 */
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#include "parse_tree.h"

extern int yylex();
extern int yyparse();
extern int yyrestart();
extern FILE * yyin;

extern int lines;
extern char * yytext;
extern int pos_end;
extern int pos_start;

parse_tree *gt;

void yyerror(const char *s);

parse_tree_node *node(const char *node_name, int children_num, ...);
%}

/* 定义%union，包含所有可能的语义值类型，这里节点类型为parse_tree_node* */
%union {
    struct _parse_tree_node *node;
}

/* 终结符定义 */
%token <node> 
    ERROR                                                        /* 错误标记 */
    ADD EQ SUB MUL DIV MOD AND OR NOT                            /* 运算符 */
    LT LET GT GET NEQ                                            /* 比较运算符 */
    INT FLOAT VOID CONST                                         /* 数据类型关键字 */
    SEMICOLON COMMA ASSIGN                                       /* 分隔符 */
    LPARENTHESIS RPARENTHESIS LBRACKET RBRACKET LBRACE RBRACE    /* 括号 */
    RETURN IF ELSE WHILE BREAK CONTINUE                          /* 关键字 */
    IDENT INTCONST FLOATCONST                                    /* 常量 */
;

/* 非终结符定义 */
%type <node> 
    Program CompUnit                                                                             /* 程序结构类 */
    Decl ConstDecl VarDecl                                                                       /* 声明类 */
    BType ConstDefList ConstDef VarDef VarDeclList                                               /* 类型与定义类 */
    Exp Cond LVal PrimaryExp Number UnaryExp MulExp AddExp RelExp EqExp LAndExp LOrExp ConstExp  /* 表达式类 */
    FuncDef FuncFParams FuncFParam FuncRParams                                                   /* 函数相关类 */
    Block BlockList BlockItem Stmt                                                               /* 语句块与语句类 */
    ConstInitVal ConstInitValList InitVal InitValList                                            /* 常量初始化与变量初始化类 */
    ConstExpList ExpList Integer Floatnum UnaryOp                                                /* 其他类 */

/* 开始符 */
%start Program

%%

// Program：程序的开始规则
Program : CompUnit { $$ = node("Program", 1, $1); gt->root = $$; }
;

// CompUnit：编译单元，可以是多个声明或函数定义
CompUnit : CompUnit Decl { $$ = node("CompUnit", 2, $1, $2); }
           | CompUnit FuncDef { $$ = node("CompUnit", 2, $1, $2); }
           | Decl { $$ = node("CompUnit", 1, $1); }
           | FuncDef { $$ = node("CompUnit", 1, $1); }

// Decl：声明，可以是常量声明或变量声明
Decl : ConstDecl { $$ = node("Decl", 1, $1); }
       | VarDecl { $$ = node("Decl", 1, $1); }

// ConstDecl：常量声明，包含类型、常量定义列表和分号
ConstDecl : CONST BType ConstDefList SEMICOLON { $$ = node("ConstDecl", 4, $1, $2, $3, $4); }

// ConstDefList：常量定义列表
ConstDefList : ConstDef { $$ = node("ConstDefList", 1, $1); }
              | ConstDefList COMMA ConstDef { $$ = node("ConstDefList", 3, $1, $2, $3); }

// BType：基本类型，可以是整型或浮点型
BType : INT { $$ = node("BType", 1, $1); }
       | FLOAT { $$ = node("BType", 1, $1); }

// ConstDef：常量定义，包含标识符、常量表达式和初始化值
ConstDef : IDENT ConstExpList ASSIGN ConstInitVal { $$ = node("ConstDef", 4, $1, $2, $3, $4); }

// ConstExpList：常量表达式列表
ConstExpList :  { $$ = node("ConstExpList", 0); }
              | ConstExpList LBRACKET ConstExp RBRACKET { $$ = node("ConstExpList", 4, $1, $2, $3, $4); }

// ConstInitVal：常量初值，可以是常量表达式或初始化列表
ConstInitVal : ConstExp  { $$ = node("ConstInitVal", 1, $1); }
              | LBRACE ConstInitValList RBRACE  { $$ = node("ConstInitVal", 3, $1, $2, $3); }
              | LBRACE RBRACE  { $$ = node("ConstInitVal", 2, $1, $2); }

// ConstInitValList：常量初值列表
ConstInitValList : ConstInitVal { $$ = node("ConstInitValList", 1, $1); }
                  | ConstInitValList COMMA ConstInitVal  { $$ = node("ConstInitValList", 3, $1, $2, $3); }

// VarDecl：变量声明，包含类型、变量定义和变量声明列表
VarDecl : BType VarDef VarDeclList SEMICOLON { $$ = node("VarDecl", 4, $1, $2, $3, $4); }

// VarDeclList：变量声明列表
VarDeclList :  { $$ = node("VarDeclList", 0); }
             | VarDeclList COMMA VarDef  { $$ = node("VarDeclList", 3, $1, $2, $3); }

// VarDef：变量定义，包含标识符、常量表达式列表和初始化值
VarDef : IDENT ConstExpList  { $$ = node("VarDef", 2, $1, $2); }
        | IDENT ConstExpList ASSIGN InitVal { $$ = node("VarDef", 4, $1, $2, $3, $4); }

// InitVal：变量初值，可以是表达式或初始化列表
InitVal : Exp  { $$ = node("InitVal", 1, $1); }
         | LBRACE InitValList RBRACE  { $$ = node("InitVal", 3, $1, $2, $3); }
         | LBRACE RBRACE  { $$ = node("InitVal", 2, $1, $2); }

// InitValList：变量初值列表
InitValList : InitVal  { $$ = node("InitValList", 1, $1); }
             | InitValList COMMA InitVal  { $$ = node("InitValList", 3, $1, $2, $3); }

// FuncDef：函数定义，包含返回类型、函数名、参数和函数体
FuncDef : BType IDENT LPARENTHESIS RPARENTHESIS Block  { $$ = node("FuncDef", 5, $1, $2, $3, $4, $5); }
          | VOID IDENT LPARENTHESIS RPARENTHESIS Block { $$ = node("FuncDef", 5, $1, $2, $3, $4, $5); }
          | VOID IDENT LPARENTHESIS FuncFParams RPARENTHESIS Block { $$ = node("FuncDef", 6, $1, $2, $3, $4, $5, $6); }
          | BType IDENT LPARENTHESIS FuncFParams RPARENTHESIS Block { $$ = node("FuncDef", 6, $1, $2, $3, $4, $5, $6); }

// FuncFParams：函数形参列表
FuncFParams : FuncFParam  { $$ = node("FuncFParams", 1, $1); }
              | FuncFParams COMMA FuncFParam  { $$ = node("FuncFParams", 3, $1, $2, $3); }

// FuncFParam：函数形参，包含类型和标识符，或者带有数组维度的参数
FuncFParam : BType IDENT  { $$ = node("FuncFParam", 2, $1, $2); }
            | BType IDENT LBRACKET RBRACKET ExpList  { $$ = node("FuncFParam", 5, $1, $2, $3, $4, $5); }

// ExpList：表达式列表
ExpList :  { $$ = node("ExpList", 0); }
         | ExpList LBRACKET Exp RBRACKET { $$ = node("ExpList", 4, $1, $2, $3, $4); }

// Block：语句块，由左大括号、语句列表和右大括号组成
Block : LBRACE BlockList RBRACE  { $$ = node("Block", 3, $1, $2, $3); }

// BlockList：语句块中的语句列表
BlockList :  { $$ = node("BlockList", 0); }
           | BlockList BlockItem  { $$ = node("BlockList", 2, $1, $2); }

// BlockItem：语句块项，可以是声明或语句
BlockItem : Decl  { $$ = node("BlockItem", 1, $1); }
            | Stmt { $$ = node("BlockItem", 1, $1); }

// Stmt：语句，可以是赋值语句、表达式语句、条件语句等
Stmt : LVal ASSIGN Exp SEMICOLON { $$ = node("Stmt", 4, $1, $2, $3, $4); }
      | Exp SEMICOLON  { $$ = node("Stmt", 2, $1, $2); }
      | SEMICOLON  { $$ = node("Stmt", 1, $1); }
      | Block  { $$ = node("Stmt", 1, $1); }
      | IF LPARENTHESIS Cond RPARENTHESIS Stmt  { $$ = node("Stmt", 5, $1, $2, $3, $4, $5); }
      | IF LPARENTHESIS Cond RPARENTHESIS Stmt ELSE Stmt  { $$ = node("Stmt", 7, $1, $2, $3, $4, $5, $6, $7); }
      | WHILE LPARENTHESIS Cond RPARENTHESIS Stmt  { $$ = node("Stmt", 5, $1, $2, $3, $4, $5); }
      | BREAK SEMICOLON  { $$ = node("Stmt", 2, $1, $2); }
      | CONTINUE SEMICOLON  { $$ = node("Stmt", 2, $1, $2); }
      | RETURN Exp SEMICOLON  { $$ = node("Stmt", 3, $1, $2, $3); }
      | RETURN SEMICOLON  { $$ = node("Stmt", 2, $1, $2); }

// Exp：表达式，表示加法表达式
Exp : AddExp  { $$ = node("Exp", 1, $1); }

// Cond：条件表达式，表示逻辑或表达式
Cond : LOrExp  { $$ = node("Cond", 1, $1); }

// LVal：左值表达式，包含标识符和表达式列表
LVal : IDENT ExpList  { $$ = node("LVal", 2, $1, $2); }

// PrimaryExp：基本表达式，包含括号中的表达式、左值或数值
PrimaryExp : LPARENTHESIS Exp RPARENTHESIS  { $$ = node("PrimaryExp", 3, $1, $2, $3); }
            | LVal  { $$ = node("PrimaryExp", 1, $1); }
            | Number  { $$ = node("PrimaryExp", 1, $1); }

// Number：数值，包含整数或浮点数
Number : Integer  { $$ = node("Number", 1, $1); }
         | Floatnum { $$ = node("Number", 1, $1); }

// UnaryExp：一元表达式，可以是基本表达式、标识符调用、或一元操作符
UnaryExp : PrimaryExp  { $$ = node("UnaryExp", 1, $1); }
           | IDENT LPARENTHESIS FuncRParams RPARENTHESIS { $$ = node("UnaryExp", 4, $1, $2, $3, $4); }
           | IDENT LPARENTHESIS RPARENTHESIS  { $$ = node("UnaryExp", 3, $1, $2, $3); }
           | UnaryOp UnaryExp  { $$ = node("UnaryExp", 2, $1, $2); }

// UnaryOp：单目运算符，包含加、减、非等操作符
UnaryOp : ADD  { $$ = node("UnaryOp", 1, $1); }
          | SUB { $$ = node("UnaryOp", 1, $1); }
          | NOT { $$ = node("UnaryOp", 1, $1); }

// FuncRParams：函数实参列表，包含表达式
FuncRParams : Exp  { $$ = node("FuncRParams", 1, $1); }
              | FuncRParams COMMA Exp  { $$ = node("FuncRParams", 3, $1, $2, $3); }

// MulExp：乘除模表达式
MulExp : UnaryExp  { $$ = node("MulExp", 1, $1); }
         | MulExp MUL UnaryExp  { $$ = node("MulExp", 3, $1, $2, $3); }
         | MulExp DIV UnaryExp  { $$ = node("MulExp", 3, $1, $2, $3); }
         | MulExp MOD UnaryExp  { $$ = node("MulExp", 3, $1, $2, $3); }

// AddExp：加减表达式
AddExp : MulExp  { $$ = node("AddExp", 1, $1); }
         | AddExp ADD MulExp  { $$ = node("AddExp", 3, $1, $2, $3); }
         | AddExp SUB MulExp  { $$ = node("AddExp", 3, $1, $2, $3); }

// RelExp：关系表达式，包含大于、小于等操作符
RelExp : AddExp  { $$ = node("RelExp", 1, $1); }
         | RelExp LT AddExp  { $$ = node("RelExp", 3, $1, $2, $3); }
         | RelExp LET AddExp  { $$ = node("RelExp", 3, $1, $2, $3); }
         | RelExp GT AddExp { $$ = node("RelExp", 3, $1, $2, $3); }
         | RelExp GET AddExp { $$ = node("RelExp", 3, $1, $2, $3); }

// EqExp：相等性表达式，包含等于、不等于操作符
EqExp : RelExp  { $$ = node("EqExp", 1, $1); }
        | EqExp EQ RelExp  { $$ = node("EqExp", 3, $1, $2, $3); }
        | EqExp NEQ RelExp { $$ = node("EqExp", 3, $1, $2, $3); }

// LAndExp：逻辑与表达式，包含 AND 操作符
LAndExp : EqExp  { $$ = node("LAndExp", 1, $1); }
          | LAndExp AND EqExp  { $$ = node("LAndExp", 3, $1, $2, $3); }

// LOrExp：逻辑或表达式，包含 OR 操作符
LOrExp : LAndExp  { $$ = node("LOrExp", 1, $1); }
         | LOrExp OR LAndExp  { $$ = node("LOrExp", 3, $1, $2, $3); }

// ConstExp：常量表达式
ConstExp : AddExp  { $$ = node("ConstExp", 1, $1); }

// Integer：整数常量
Integer : INTCONST  { $$ = node("Integer", 1, $1); }

// Floatnum：浮点数常量
Floatnum : FLOATCONST  { $$ = node("Floatnum", 1, $1); }

%%

/* 错误报告函数 */
void yyerror(const char * s)
{
    fprintf(stderr, "error at line %d column %d: %s\n", lines, pos_start, s);
    exit(1);
}

/* 从文件或标准输入解析输入，并打印解析结果 */
parse_tree *parse(const char *input_path)
{
    if (input_path != NULL) {
        if (!(yyin = fopen(input_path, "r"))) {
            fprintf(stderr, "[ERR] Open input file %s failed.\n", input_path);
            exit(1);
        }
    } else {
        yyin = stdin;
    }
    lines = pos_start = pos_end = 1;
    gt = new_parse_tree();
    yyrestart(yyin);
    yyparse();
    return gt;
}

/* 辅助函数，用于快速构建树节点 */
parse_tree_node *node(const char *name, int children_num, ...)
{
    parse_tree_node *p = new_parse_tree_node(name);
    parse_tree_node *child;
    if (children_num == 0) {
        child = new_parse_tree_node("epsilon");
        parse_tree_add_child(p, child);
    } else {
        va_list ap;
        va_start(ap, children_num);
        for (int i = 0; i < children_num; ++i) {
            child = va_arg(ap, parse_tree_node *);
            parse_tree_add_child(p, child);
        }
        va_end(ap);
    }
    return p;
}